package protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * @author ZhuQi
 * @ClassName MessageCodec
 * @Date 2023/1/12 15:25
 * @Version 1.0
 * @Description 实习自己的自定义消息的解码器 必须 和 LengthFileBaseFrameDecoder 一起使用，确认接收到的 ByteBuf 是完整的
 */
@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {

    /**
     * 出站前编码
     *
     * @param ctx
     * @param msg
     * @param out
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        log.info("出站方法调用 msg:{}", msg);
        // 1. 魔数 （4个字节）
        out.writeInt(1);
        // 2. 版本号  （1个字节）
        out.writeByte(1);
        // 3. 序列化算法 0：jdk 1.json （1个字节）
        out.writeByte(0);
        // 4. 指令类型 （1个字节）
        out.writeByte(msg.getMessageType());
        // 5. 请求序号 （4个字节）
        out.writeInt(msg.getSequenceId());
        // 无意义，对其用
        out.writeByte(1);

        // 使用 JDK 序列化 获取 Byte 数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(msg);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        // 6. 正文长度 （4个字节）
        out.writeInt(bytes.length);
        // 7. 消息正文 （n个字节）
        out.writeBytes(bytes);
        log.info("out:{}", out);
        ctx.write(out);
    }

    /**
     * 入站的时候进行解码的
     *
     * @param ctx
     * @param in
     * @param out
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // read 方法会移动 readIndex
        // 1 魔数 （4个字节）
        int magicNum = in.readInt();
        log.info("magicNum:{}", magicNum);

        // 2 版本号 （1个字节）
        byte version = in.readByte();
        log.info("version:{}", version);

        // 3 序列化算法 （1个字节）
        byte serialize = in.readByte();
        log.info("serialize:{}", serialize);

        // 4 指令类型 （1个字节）
        byte business = in.readByte();
        log.info("business:{}", business);

        // 5 请求序号 （4个字节）
        int num = in.readInt();
        log.info("num:{}", num);

        // 6 对其字节，无意义
        in.readByte();

        // 7 正文长度
        int length = in.readInt();
        log.info("length:{}", length);


        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);

        // 序列化算法 JDK
        if (serialize == 0) {
            ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
            Message message = (Message) objectInputStream.readObject();
            log.info("message:{}", message);
            // 添加到 List 给下一个 Handler 使用
            out.add(message);
        }

    }
}
